package com.database.objects;

import static com.load.utils.IssueUtil.*;

import java.io.InputStream;
import java.net.URL;
import java.util.*;
import java.util.regex.Pattern;

import javax.persistence.*;

import com.google.common.collect.Lists;
import com.load.utils.KeyIssue;
import com.metrics.objects.Metric;

public class TrackerRepository extends Repository {

	private static final long serialVersionUID = 8090252171056075193L;

	public static final List<Type> TYPES = Lists.newArrayList(Type.TASK, Type.ENHANCEMENT, Type.DEFECT);

	public static final List<Status> STATUS = Lists.newArrayList(Status.OPEN, Status.CLOSED, Status.TOTAL);

	public static final List<Metric> METRICS = Lists.newArrayList(Metric.COUNTER_OF_ELEMENTS);

	public static final List<Distribution> DISTRIBUTIONS = Lists.newArrayList(Distribution.GOOGLE_CODE, Distribution.SOURCEFORGE);

	private static final String URL_CODE_GOOGLE = "http://code.google.com/p/:name/issues/csv?can=1&q=&colspec=ID%20Type%20Status%20Priority%20Milestone%20Owner%20Summary";

	private static final String URL_SOURCEFORGE = "http://sourceforge.net/search/index.php?group_id=:groupId&offset=:offset&type_of_search=artifact&q=&artifact_id=&submitted_by=&assigned_to=&open_date_start=&open_date_end=&last_update_date_start=&last_update_date_end=&form_submit=Search";

	private static final String BASE_ISSUE_PATTERN = "<tr> <td class=\"p.\"> (.+?) </td> <td> (.+?) </td> <td> <a href=\"/tracker/\\?group_id=:groupId&atid=(.+?)\">(.+?)</a> </td> <td class=\"summary\"> <a href=\"/tracker/index.php\\?func=detail&aid=(.+?)&group_id=:groupId&atid=(.+?)\">(.+?)</a> </td> <td> (.+?) </td> <td> (.+?) </td> <td> (.+?);(.+?);(.+?) </td> <td> (.+?) </td>";

	private static final String BASE_DEVELOPER_PATTERN = "<a href=\"/users/(.+?)/";

	@Column(name = "tra_group", nullable = false)
	private String group = "";

	@Enumerated(EnumType.STRING)
	@Column(name = "tra_distribution", nullable = false)
	private Distribution distribution = Distribution.UNKNOWN;

	@Column(name = "tra_url", nullable = false)
	private String url = "";

	@Transient
	private List<Map<KeyIssue, String>> textIssues = new ArrayList<Map<KeyIssue, String>>();

	public TrackerRepository() {

	}

	public String getGroup() {
		return group;
	}

	public void setGroup(String group) {
		this.group = group;
	}

	public Distribution getDistribution() {
		return distribution;
	}

	public void setDistribution(Distribution distribution) {
		this.distribution = distribution;
	}

	public String getUrl() {
		return url;
	}

	public List<Map<KeyIssue, String>> getTextIssues() {
		return textIssues;
	}

	public float getNumIssues() {
		return textIssues.size();
	}

	public void constructUrl(String name) {
		if (distribution.isGoogleCode()) {
			url = URL_CODE_GOOGLE.replace(":name", name);
		} else if (distribution.isSourceForge()) {
			url = URL_SOURCEFORGE.replace(":groupId", group);
		}
	}

	public boolean hasGoogleCodeDistribution() {
		return distribution.isGoogleCode();
	}

	public void constructTextIssues() throws Exception {
		checkGoogleCodeTextIssues();
		checkSourceForgeTextIssues();
	}

	private void checkGoogleCodeTextIssues() throws Exception {
		if (distribution.isGoogleCode()) {
			InputStream input = new URL(url).openStream();
			textIssues = formatGoogleCodeDistribution(input);
		}
	}

	private void checkSourceForgeTextIssues() throws Exception {
		if (distribution.isSourceForge()) {
			Pattern issuePattern = Pattern.compile(BASE_ISSUE_PATTERN.replace(":groupId", group));
			Pattern developerPattern = Pattern.compile(BASE_DEVELOPER_PATTERN);
			url = url.replace(":groupId", group);

			textIssues = formatSourceForgeDistribution(url, issuePattern, developerPattern);
		}
	}

	@Override
	public boolean isVersionRepository() {
		return false;
	}

	@Override
	public boolean isTrackerRepository() {
		return true;
	}

	@Override
	public List<Type> getTypes() {
		return TYPES;
	}

	@Override
	public List<Status> getStatus() {
		return STATUS;
	}

	@Override
	public List<Metric> getMetrics() {
		return METRICS;
	}

	public static List<Distribution> getDistributions() {
		return DISTRIBUTIONS;
	}

}